package spring.resources;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import spring.exceptions.BeanInitializationException;
import spring.factory.SingletonBeanRegistry;
import spring.parsing.XmlNodeType;
import spring.parsing.XmlParser;
import spring.parsing.XmlParserFactory;
import utils.ClassUtils;
import utils.LogUtils;
import utils.ResourceUtils;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ClassPathXmlReader {

    public static final String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    public SingletonBeanRegistry singletonBeanRegistry;

    public ClassPathXmlReader(SingletonBeanRegistry singletonBeanRegistry) {
        this.singletonBeanRegistry = singletonBeanRegistry;
    }

//    public static void main(String[] args) throws Exception {
//        ClassPathXmlReader reader = new ClassPathXmlReader();
//        reader.read("classpath*:/spring/**/spring-*.xml");
//    }

    public void read(String path) throws Exception {
        // 解析路径信息
        XmlBeanDefinitionBean definitionBean = parsePathInfo(path);
        // 读取符合条件的文件
        parseXml(definitionBean);
    }

    private XmlBeanDefinitionBean parsePathInfo(String path) throws IOException {
        XmlBeanDefinitionBean definitionBean = new XmlBeanDefinitionBean();
        definitionBean.setReadEntirePackage(isReadEntirePackage(path));
        definitionBean.setReadAllFile(isReadAllFile(path));
        definitionBean.setGlobEntireFile(isGlobEntireFile(path));
        definitionBean.setClassLoader(ClassUtils.getDefaultClassLoader());
        setFilePath(path, definitionBean);
        return definitionBean;
    }

    private void setFilePath(String path, XmlBeanDefinitionBean definitionBean) throws IOException {
        String rootDirPath = determineRootDir(path);
        String location = rootDirPath.substring(CLASSPATH_ALL_URL_PREFIX.length());
        URL rootUrl = definitionBean.getClassLoader().getResource(location);
        assert rootUrl != null;
        File rootFile = new File(rootUrl.getFile());
        String subPattern = path.substring(rootDirPath.length());
        definitionBean.setRootPath(location);
        definitionBean.setRootUrl(rootUrl);
        definitionBean.setChildPath(subPattern);
        List<InputStream> fileStreams = ResourceUtils.parseConfigs(rootFile, definitionBean.isReadAllFile(), subPattern);
        definitionBean.setFileInputStreams(fileStreams);
    }

    private boolean isReadEntirePackage(String path) {
        return path.contains(CLASSPATH_ALL_URL_PREFIX);
    }

    private boolean isReadAllFile(String path) {
        return path.contains("/**/");
    }

    private boolean isGlobEntireFile(String path) {
        return path.substring(path.lastIndexOf('/')).contains("*");
    }

    private String determineRootDir(String location) {
        int prefixEnd = location.indexOf(':') + 1;
        int rootDirEnd = location.length();
        while (rootDirEnd > prefixEnd && isPattern(location.substring(prefixEnd, rootDirEnd))) {
            rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1;
        }
        if (rootDirEnd == 0) {
            rootDirEnd = prefixEnd;
        }
        return location.substring(0, rootDirEnd);
    }

    public boolean isPattern(String path) {
        boolean uriVar = false;
        for (int i = 0; i < path.length(); i++) {
            char c = path.charAt(i);
            if (c == '*' || c == '?') {
                return true;
            }
            if (c == '{') {
                uriVar = true;
                continue;
            }
            if (c == '}' && uriVar) {
                return true;
            }
        }
        return false;
    }

    public void parseXml(XmlBeanDefinitionBean bean) {
        SAXReader saxReader = new SAXReader();
        List<InputStream> fileStreams = bean.getFileInputStreams();
        if (fileStreams.isEmpty()) {
            System.err.println("======== 没有可用的配置文件 ========");
            return;
        }
        // 延迟设置属性列表
        XmlParserFactory xmlParserFactory = XmlParserFactory.getInstance();
        Map<String, Element> elementMap = new HashMap<>(20);
        fileStreams.forEach(steam -> {
            try {
                Document document = saxReader.read(steam);
                Element rootElement = document.getRootElement();
                if (XmlNodeType.noRootElement(rootElement.getName())) {
                    throw new BeanInitializationException("当前跟标签配置错误，beans标签为根标签。实际配置为：" + rootElement.getName());
                }
                rootElement.elements().forEach(element -> elementMap.put(element.attributeValue("id"), element));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
        // 将 dom 元素添加到缓存池
        DomElementHolder.refreshElement(elementMap);
        // 解析配置文件中的所有节点
        elementMap.values().forEach(element -> {
            XmlNodeType nodeType = XmlNodeType.nameOf(element.getName());
            XmlParser beanParser = xmlParserFactory.create(nodeType, singletonBeanRegistry);
            beanParser.parse(element);
        });
        LogUtils.debug("初始化结束。");
        DomElementHolder.destroy(); // 销毁加载缓存
    }

}
